#include <exception>
#include "scripting.h"

Scripting::Scripting()
{
	podmath = new PodMath();
	L = luaL_newstate();

	static const luaL_Reg lualibs [] =
	{
		{"base", luaopen_base },
		{NULL, NULL}
	};

	const luaL_Reg *lib = lualibs;
	for (; lib->func != NULL; lib++)
	{
		lib->func(L);
		lua_settop(L,0);
	}

	lua_register(L, "runScript", wrap_runScript);

	//Register the FAST Math functions -- "Are we really calling Assembly from Lua!? :D"
	lua_register(L, "getMax", wrap_getMax);
	lua_register(L, "getMin", wrap_getMin);
	lua_register(L, "fast_sqrt", wrap_fast_sqrt);
	lua_register(L, "fast_invsqrt", wrap_fast_invsqrt);
	lua_register(L, "fast_invsqrtM$", wrap_fast_invsqrtM$);
	lua_register(L, "fast_ln", wrap_fast_ln);
	lua_register(L, "fast_sin", wrap_fast_sin);
	lua_register(L, "fast_cos", wrap_fast_cos);
	lua_register(L, "fast_tan", wrap_fast_tan);
	lua_register(L, "fast_csc", wrap_fast_csc);
	lua_register(L, "fast_sec", wrap_fast_sec);
	lua_register(L, "fast_cot", wrap_fast_cot);
	lua_register(L, "fast_arcsin", wrap_fast_arcsin);
	lua_register(L, "fast_arccos", wrap_fast_arccos);
	lua_register(L, "fast_arctan", wrap_fast_arctan);
	lua_register(L, "fast_abs", wrap_fast_abs);
}

Scripting::~Scripting()
{
	lua_close(L);
}

int Scripting::doString(char* lua_text)
{
	try
	{
		luaL_dostring(L, lua_text);
	}
	catch(std::exception &e)
	{
		error = (char *)e.what();
		return SCRIPT_FAIL;
	}
	catch(...)
	{
		error = "Unknown Lua Error";
		return SCRIPT_FAIL;
	}
	return SCRIPT_SUCCESS;
}

int Scripting::runScript(char* lua_file)
{
	try
	{
		luaL_dofile(L, lua_file);
	}
	catch (std::exception &e)
	{
		error = (char *)e.what();
		return SCRIPT_FAIL;
	}
	catch (...)
	{
		error = "Unknown Lua Error";
		return SCRIPT_FAIL;
	}
	return SCRIPT_SUCCESS;
}


//Wrapper functions for Lua Handling
int Scripting::wrap_runScript(lua_State *_L)
{
	if (lua_gettop(_L) != 1) { return SCRIPT_FAIL; }
	Scripting *scrEngine = new Scripting();
	return (scrEngine->runScript((char *)lua_tostring(_L, 1)) != SCRIPT_FAIL) ? SCRIPT_SUCCESS : SCRIPT_FAIL;
}


//Wrapper functions for FAST MATH (PodMath)
int Scripting::wrap_getMax(lua_State *_L)
{
	if (lua_gettop(_L) != 2) { return 0; }
	PodMath *podmath = new PodMath();
	lua_pushnumber(_L, podmath->getMax<float>(lua_tonumber(_L, 1), lua_tonumber(_L, 2)));
	delete podmath;
	return 1;
}

int Scripting::wrap_getMin(lua_State *_L)
{
	if (lua_gettop(_L) != 2) { return 0; }
	PodMath *podmath = new PodMath();
	lua_pushnumber(_L, podmath->getMin<float>(lua_tonumber(_L, 1), lua_tonumber(_L, 2)));
	delete podmath;
	return 1;
}

/* // NEED TO FIX! - Zach
int Scripting::wrap_fast_rand(lua_State *_L)
{
	PodMath *podmath = new PodMath();
	lua_pushnumber(_L, podmath->fast_rand());
	delete podmath;
	return 1;
}
*/

int Scripting::wrap_fast_sqrt(lua_State *_L)
{
	if (lua_gettop(_L) != 1) { return 0; }
	PodMath *podmath = new PodMath();
	lua_pushnumber(_L, podmath->fast_sqrt(lua_tonumber(_L, 1)));
	delete podmath;
	return 1;
}

int Scripting::wrap_fast_invsqrt(lua_State *_L)
{
	if (lua_gettop(_L) != 1) { return 0; }
	PodMath *podmath = new PodMath();
	lua_pushnumber(_L, podmath->fast_invsqrt(lua_tonumber(_L, 1)));
	delete podmath;
	return 1;
}

int Scripting::wrap_fast_invsqrtM$(lua_State *_L)
{
	if (lua_gettop(_L) != 1) { return 0; }
	PodMath *podmath = new PodMath();
	lua_pushnumber(_L, podmath->fast_invsqrtM$(lua_tonumber(_L, 1)));
	delete podmath;
	return 1;
}

int Scripting::wrap_fast_ln(lua_State *_L)
{
	if (lua_gettop(_L) != 1) { return 0; }
	PodMath *podmath = new PodMath();
	lua_pushnumber(_L, podmath->fast_ln(lua_tonumber(_L, 1)));
	delete podmath;
	return 1;
}

int Scripting::wrap_fast_sin(lua_State *_L)
{
	if (lua_gettop(_L) != 1) { return 0; }
	PodMath *podmath = new PodMath();
	lua_pushnumber(_L, podmath->fast_sin(lua_tonumber(_L, 1)));
	delete podmath;
	return 1;
}

int  Scripting::wrap_fast_cos(lua_State *_L)
{
	if (lua_gettop(_L) != 1) { return 0; }
	PodMath *podmath = new PodMath();
	lua_pushnumber(_L, podmath->fast_cos(lua_tonumber(_L, 1)));
	delete podmath;
	return 1;
}

int Scripting::wrap_fast_tan(lua_State *_L)
{
	if (lua_gettop(_L) != 1) { return 0; }
	PodMath *podmath = new PodMath();
	lua_pushnumber(_L, podmath->fast_tan(lua_tonumber(_L, 1)));
	delete podmath;
	return 1;
}

int Scripting::wrap_fast_csc(lua_State *_L)
{
	if (lua_gettop(_L) != 1) { return 0; }
	PodMath *podmath = new PodMath();
	lua_pushnumber(_L, podmath->fast_csc(lua_tonumber(_L, 1)));
	delete podmath;
	return 1;
}

int Scripting::wrap_fast_sec(lua_State *_L)
{
	if (lua_gettop(_L) != 1) { return 0; }
	PodMath *podmath = new PodMath();
	lua_pushnumber(_L, podmath->fast_sec(lua_tonumber(_L, 1)));
	delete podmath;
	return 1;
}

int Scripting::wrap_fast_cot(lua_State *_L)
{
	if (lua_gettop(_L) != 1) { return 0; }
	PodMath *podmath = new PodMath();
	lua_pushnumber(_L, podmath->fast_cot(lua_tonumber(_L, 1)));
	delete podmath;
	return 1;
}

int Scripting::wrap_fast_arcsin(lua_State *_L)
{
	if (lua_gettop(_L) != 1) { return 0; }
	PodMath *podmath = new PodMath();
	lua_pushnumber(_L, podmath->fast_arcsin(lua_tonumber(_L, 1)));
	delete podmath;
	return 1;
}

int Scripting::wrap_fast_arccos(lua_State *_L)
{
	if (lua_gettop(_L) != 1) { return 0; }
	PodMath *podmath = new PodMath();
	lua_pushnumber(_L, podmath->fast_arccos(lua_tonumber(_L, 1)));
	delete podmath;
	return 1;
}

int Scripting::wrap_fast_arctan(lua_State*_L)
{
	if (lua_gettop(_L) != 1) { return 0; }
	PodMath *podmath = new PodMath();
	lua_pushnumber(_L, podmath->fast_arctan(lua_tonumber(_L, 1)));
	delete podmath;
	return 1;
}

int Scripting::wrap_fast_abs(lua_State *_L)
{
	PodMath *podmath = new PodMath();
	float x = lua_tonumber(_L, 1);
	lua_pushnumber(_L, podmath->fast_abs<float>(x));
	delete podmath;
	return 1;
}

